package org.meeting.radish.oj;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class OjService {

    String fileName;
    String code;
    String language;

    /**
     * @param fileName 文件名
     * @param code     文件内容，代码
     * @param language 语言
     */
    public OjService(String fileName, String code, String language) {
        this.fileName = fileName;
        this.code = code;
        this.language = language;
    }

    /**
     * 写入文件
     */
    public boolean saveCodeFile() throws CodeTypeException, IOException {
        if (!OjParameter.OjProperties.codeTypeAndRun.containsKey(language)) {
            throw new CodeTypeException();
        }

        File dir = new File(OjParameter.OjProperties.codePath);
        if (!dir.exists()) {
            dir.mkdir();
        }

        String fileSuffix = OjParameter.OjProperties.codeTypeAndRun.get(language).get(0);
        String allPath = String.format("%s%s%s.%s",
                OjParameter.OjProperties.codePath, File.separator, fileName, fileSuffix);

        File file = new File(allPath);
        if (!file.exists()) {
            file.createNewFile();
            log.info("文件已创建");
        }

        BufferedWriter bw = new BufferedWriter(new FileWriter(file));
        bw.write(code);
        bw.close();
        log.info("文件写入完毕");
        return true;
    }

    /**
     * @return 编译和运行指令
     */
    public Map<String, String> getCompileAndRunOrder() {
        List<String> orders = OjParameter.OjProperties.codeTypeAndRun.get(language);
        if (orders.size() == 2) {
            return new HashMap<>() {{
                put(OjParameter.OjExecute.RUN, orders.get(1).replaceAll(OjParameter.OjProperties.fileNameSign, fileName));
            }};
        } else if (orders.size() == 3) {
            return new HashMap<>() {{
                put(OjParameter.OjExecute.COMPILE, orders.get(1).replaceAll(OjParameter.OjProperties.fileNameSign, fileName));
                put(OjParameter.OjExecute.RUN, orders.get(2).replaceAll(OjParameter.OjProperties.fileNameSign, fileName));
            }};
        }
        return null;
    }

    /**
     * 读取输出
     */
    private String execRead(BufferedReader br) throws IOException {
        StringBuffer sb = new StringBuffer();
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }

        return sb.toString();
    }

    ;

    /**
     * 编译
     *
     * @param command 编译指令
     */
    public Map<Boolean, String> compile(String command) throws IOException, InterruptedException {
        Process exec = Runtime.getRuntime().exec(OjParameter.OjProperties.runSh);
        execWrite(new BufferedWriter(new OutputStreamWriter(exec.getOutputStream())), command, null);
        exec.waitFor();
//        Thread.sleep(OjParameter.OjProperties.runTime);
        Map<Boolean, String> map = new HashMap<>();
        if (exec.exitValue() == 0) {
            map.put(true, "编译成功");
        } else {
            BufferedReader br = new BufferedReader(new InputStreamReader(exec.getErrorStream()));
            map.put(false, execRead(br));
        }

        exec.destroy();
        return map;
    }

    /**
     * 无参运行
     *
     * @param command 指令
     * @param out     结果
     */
    public Map<Boolean, String> run(String command, String out) throws IOException {
        return run(command, null, out);
    }

    /**
     * 有参运行
     *
     * @param command 指令
     * @param in      入参
     * @param out     结果
     */
    public Map<Boolean, String> run(String command, String in, String out) throws IOException {
        Process exec = Runtime.getRuntime().exec(OjParameter.OjProperties.runSh);
        execWrite(new BufferedWriter(new OutputStreamWriter(exec.getOutputStream())), command, in);
        try {
            Thread.sleep(OjParameter.OjProperties.runTime);
            return judge(exec, out);
        } catch (InterruptedException e) {
            return new HashMap<>() {{
                put(false, e.getMessage());
            }};
        } finally {
            exec.destroy();
        }
    }

    private void execWrite(BufferedWriter bw, String command, String in) throws IOException {
        bw.write(String.format("cd %s && %s", OjParameter.OjProperties.codePath, command));
        bw.newLine();
        if (in != null && !in.equals("")) {
            bw.write(in);
            bw.newLine();
        }
        bw.close();
    }

    private Map<Boolean, String> judge(Process process, String out) throws IOException {
        BufferedReader br;
        if (process.exitValue() == 0) {
            br = new BufferedReader(new InputStreamReader(process.getInputStream()));
        } else {
            br = new BufferedReader(new InputStreamReader(process.getErrorStream()));
        }

        String answer = execRead(br).trim();
        return new HashMap<>() {{
            put(answer.equals(out), answer);
        }};
    }


}
